package com.boot.utils;

import cn.hutool.core.thread.ThreadUtil;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

/**
 * @author zhangsongwei
 * created of 2024/8/14 17:32 for com.boot.utils
 */
@Slf4j
public class RetryUtils {

    /**
     * 函数式接口，用于封装需要重试的业务逻辑。
     */
    @FunctionalInterface
    public interface RetryOperation<T, R> {
        R execute(T t) ;
    }

    /**
     * 重试方法。
     * @param operation 需要重试的业务逻辑
     * @param maxRetrys 最大尝试次数
     * @param delayMillis 两次尝试之间的延迟时间（毫秒）
     * @param predicate 是否进行重试的断言
     * @param <T> 输入参数类型
     * @param <R> 返回值类型
     * @return 操作的结果
     */
    public static <T, R> R retry(RetryOperation<T, R> operation, Predicate<R> predicate,int maxRetrys, long delayMillis, T t) {
        int retryCount = 0;
        R result = operation.execute(t);
        while (retryCount++ < maxRetrys-1 && !predicate.test(result)) {
            ThreadUtil.safeSleep(delayMillis);
            log.info("第{}次重试",retryCount);
            result = operation.execute(t);
        }
        return result; // This line should never be reached.
    }

    /**
     * 重试方法。
     * @param operation 需要重试的业务逻辑
     * @param maxRetrys 最大尝试次数
     * @param delayMillis 两次尝试之间的延迟时间（毫秒）
     * @param predicate 是否进行重试的断言
     * @param <R> 返回值类型
     * @return 操作的结果
     */
    public static <R> R retry(Supplier<R> operation, Predicate<R> predicate,int maxRetrys, long delayMillis) {
        int retryCount = 0;
        R result = operation.get();
        while (retryCount++ < maxRetrys-1 && !predicate.test(result)) {
            ThreadUtil.safeSleep(delayMillis);
            log.info("第{}次重试",retryCount);
            result = operation.get();
        }
        return result; // This line should never be reached.
    }

    public static void main(String[] args) {
        // 示例: 使用RetryUtil进行重试
        int res = retry(
            (order)-> 0,
            (result)->result>0,
            3, // 最多尝试3次
            1000, // 每次重试之间等待1秒
            "failure"
        );
        System.out.println("result: " + res);
        String url = "https://www.baidu.com";
        String res1 = retry(
            ()-> HttpUtils.doGet(url),
            (result)-> StringUtils.isNotBlank(result),
            3, // 最多尝试3次
            1000 // 每次重试之间等待1秒
        );
        System.out.println("result: " + res);
    }


}
